import { Inject } from '../decorates/inject';
import { Draw } from './draw';
import { ICellBase } from '../interfaces/cell';
import { Subject } from 'rxjs';
import { Md5 } from 'ts-md5';
@Inject()
export class Config{
    private defaultCellHash: string = '';
    protected rowHeights: number[] = [];
    protected colWidths: number[] = [];
    protected defRowHeight: number = 17;
    protected defColWidht: number = 72;
    protected _startRow: number = 0;
    protected _visualMaxRow: number = 0;
    protected _visualMaxCol: number = 0;
    protected _startCol: number = 0;
    public rowHeaderColor = '#f0f0f0';
    public colHeaderColor = '#f0f0f0';
    public rowHeaderHeight = 24;
    public colHeaderWidth = 36;
    public headerBorderColor = '#ccc';
    public datas: any[] = [];
    public availableRow: number = 70;
    public availableCol: number = 40;
    public visualAreaChange: Subject<{type: 'startRow'|'startCol'|'visualMaxRow'|'visualMaxCol'}> = new Subject();
    constructor(protected draw: Draw) {

    }
    public zInit() {
        let cell = this.getDefaultCell(0,0);
        this.defaultCellHash = (Md5.hashStr(JSON.stringify(cell)) as string).toLowerCase();
        // let 
    }
    public getVisualBoundry() {

    }
    public get startRow() {
        return this._startRow;
    }
    public set startRow(val: number) {
        if(this._startRow == val || val < 0) return;  
        this._startRow = val;
        this.visualAreaChange.next({type: 'startRow'});
    }
    public get startCol() {
        return this._startCol;
    }
    public set startCol(val: number) {
        if( this._startCol == val || val < 0) return;
        this._startCol = val;
        this.visualAreaChange.next({type: 'startCol'});
    }
    public get visualMaxRow() {
        return this._visualMaxRow;
    }
    public set visualMaxRow(val: number) {
        if(this._visualMaxRow == val) return;
        this._visualMaxRow = val;
        this.visualAreaChange.next({type: 'visualMaxRow'});
    }
    public get visualMaxCol() {
        return this._visualMaxCol;
    }
    public set visualMaxCol(val: number) {
        if(this._visualMaxCol == val) return;
        this._visualMaxCol = val;
        this.visualAreaChange.next({type: 'visualMaxCol'});
    }
    public setConfig(conf: {[key: string]: any}) {
        try {
            for(let key in conf) {
                (<any>this)[key] = conf[key];
            }            
        } catch (error) {
            console.warn('config wrong!')
        }
    }
    public getRowHeight(start: number, end: number = -1) {
        if(end == -1) {
            end = start + 1;
        }
        let total = 0;
        for(let i = start; i < end; i++) {
            if(this.rowHeights[i] ==  undefined) {
                total += this.defRowHeight;
            }else{
                total += this.rowHeights[i];
            }
        }
        return total;
    }
    public setRowHeight(row: number, height: number) {
        if(this.rowHeights.length < row) {
            let arr = new Array(row - this.rowHeights.length).fill(this.defRowHeight);
            this.rowHeights = this.rowHeights.concat(arr);
        }
        this.rowHeights[row] = height;
        this.visualAreaChange.next();
    }
    public setColWidth(col: number, width: number) {
        if(this.colWidths.length < col) {
            let arr = new Array(col - this.rowHeights.length).fill(this.defColWidht);
            this.colWidths = this.colWidths.concat(arr);
        }
        this.colWidths[col] = width;
        this.visualAreaChange.next();
    }
    public getColWidth(start: number, end: number = -1) {
        if(end == -1) {
            end = start + 1;
        }
        let total = 0;
        for(let i = start; i < end; i++) {
            if(this.colWidths[i] ==  undefined) {
                total += this.defColWidht;
            }else{
                total += this.colWidths[i];
            }
        }  
        return total;     
    }
    public getCell(row: number, col: number) {
        if(this.datas.length > row && this.datas[row] != undefined) {
            if(this.datas[row].cols[col] != undefined) {
                if(this.datas[row].cols[col] != undefined) {
                   return this.datas[row].cols[col]; 
                }else{
                    return this.getDefaultCell(row, col);
                }
            }else{
                return this.getDefaultCell(row, col);
            }
        } else {
            return this.getDefaultCell(row, col);
        }
    }
    protected getDefaultFont() {
        let font = {
            size: 12,
            horizontal: 'right',
            vertical: 'middle',
            family: 'Microsoft YaHei',
            color: '#000',
            wordWrap: ''
        }
        return font;
    }
    protected getDefaultBorder() {
        return {
            left: {
                width: 1,
                color: '#ccc',
                type: 'thin'
            },
            top: {
                width: 1,
                color: '#ccc',
                type: 'thin'
            }
        }
    }
    public getDefaultCell(row: number, col: number) {
        let cell = {
            row: row,
            col: col,
            font: this.getDefaultFont(),
            border: this.getDefaultBorder(),
            editor: 'TextEditor',
            fill: {
                color: '#fff'
            },
            merge: {
                rowspan: 1,
                colspan: 1,
                row: row,
                col: col
            }
        }
        Object.defineProperties(cell, {
            row: {
                enumerable: false
            },
            col: {
                enumerable: false
            }
        });
        return cell;
    }
    public updateCell(cell: any) {
        let defaultHash = (Md5.hashStr(JSON.stringify(this.getDefaultCell(cell.row, cell.col))) as string).toLowerCase();
        let newHash = (Md5.hashStr(JSON.stringify(cell)) as string).toLowerCase();
        // if(false){
        if(defaultHash == newHash){
            this.removeCell(cell);
        }else{
            this.addCell(cell);
        }
    }
    protected addCell(cell: any) {
        if(cell.row + 1 > this.datas.length) {
            this.datas = this.datas.concat(new Array(cell.row - this.datas.length + 1).fill(undefined));
        }
        if(this.datas[cell.row] == undefined) {
            this.datas[cell.row] = { cols: []};
        }
        if(cell.col + 1 > this.datas[cell.row].cols.length) {
            this.datas[cell.row].cols = this.datas[cell.row].cols.concat(new Array(cell.col - this.datas[cell.row].cols.length + 1).fill(undefined));
        }
        this.datas[cell.row].cols[cell.col] = cell;
    }
    protected removeCell(cell: any) {

    }
    public getPosition(start: {row: number, col: number}, end: {row: number, col: number}): [number, number, number, number] {
        let startX = this.getColWidth(this.startCol, start.col) + start.col - this.startCol + this.colHeaderWidth;
        let startY = this.getRowHeight(this.startRow, start.row) + start.row - this.startRow + this.rowHeaderHeight;
        let endX = this.getColWidth(this.startCol, end.col) + end.col - this.startCol + this.colHeaderWidth;
        let endY = this.getRowHeight(this.startRow, end.row) + end.row - this.startRow + this.rowHeaderHeight;
        return [startX, startY, endX, endY];
    }
    public traverseCells(start: ICellPosition, end: ICellPosition, callback?: (cell: any) => any) {
        let rangeCells =  [];
        for(let i = start.row; i < end.row + 1; i++) {
            for(let j = start.col; j < end.col + 1; j++) {
                let cell = this.getCell(i,j);
                rangeCells.push(cell);
                if(callback != undefined) {
                    this.updateCell(callback(cell));
                }
            }
        }
        return rangeCells;
    }
}
interface ICellPosition{
    row: number;
    col: number
}